import { UploadOutlined } from '@ant-design/icons';
import { Upload as AntdUpload } from 'antd';
import { useState, ReactNode, useRef } from 'react';

import apiClient from '@/api/apiClient';
import { Button, message } from '@/components/eai-design';
import { SvgIcon } from '@/components/icon';
import { cn } from '@/utils/cn-merge';

import type { UploadProps, UploadFile } from 'antd';

import '../styles/upload.scss';

/**
 * 自定义上传列表项渲染函数类型
 */
export interface CustomUploadListItem {
  /** 文件对象 */
  file: UploadFile;
  /** 文件索引 */
  index: number;
  /** 删除文件回调 */
  onRemove: (file: UploadFile) => void;
  /** 预览文件回调 */
  onPreview?: (file: UploadFile) => void;
  /** 下载文件回调 */
  onDownload?: (file: UploadFile) => void;
}

/**
 * 自定义上传组件属性类型
 */
export interface CustomUploadProps extends Omit<UploadProps, 'fileList' | 'onChange'> {
  /** 组件尺寸 */
  size?: 'small' | 'middle' | 'large';
  /** 上传类型 */
  variant?: 'button' | 'drag' | 'avatar' | 'picture';
  /** 是否显示上传列表 */
  showUploadList?: boolean | UploadProps['showUploadList'];
  /** 文件列表 */
  fileList?: UploadFile[];
  /** 文件变化回调 */
  onChange?: (fileList: UploadFile[]) => void;
  /** 自定义上传按钮文本 */
  buttonText?: string;
  /** 拖拽区域提示文本 */
  dragText?: string;
  /** 拖拽区域副标题 */
  dragSubText?: string;
  /** 最大文件数量 */
  maxCount?: number;
  /** 允许的文件类型 */
  accept?: string;
  /** 文件大小限制（MB） */
  maxSize?: number;
  /** 自定义样式类名 */
  className?: string;
  /** 自定义上传列表渲染 */
  customUploadList?: (item: CustomUploadListItem) => ReactNode;
  /** 是否启用自定义列表 */
  useCustomList?: boolean;
}

/**
 * 自定义上传组件
 *
 * 基于 Ant Design 的 Upload 组件封装，提供了多种上传方式和自定义选项。
 * 支持按钮上传、拖拽上传、头像上传和图片上传等多种模式。
 *
 * ## 功能特性
 * - 支持多种上传方式：按钮、拖拽、头像、图片
 * - 提供 small、default、large 三种尺寸
 * - 文件类型和大小限制
 * - 上传进度显示
 * - 文件列表管理
 * - 自定义样式和主题
 * - 完整的 TypeScript 类型支持
 *
 * ## 参数说明
 * @param size - 组件尺寸，可选 'small' | 'default' | 'large'，默认为 'default'
 * @param variant - 上传类型，可选 'button' | 'drag' | 'avatar' | 'picture'，默认为 'button'
 * @param showUploadList - 是否显示上传列表，默认为 true
 * @param fileList - 文件列表，受控模式使用
 * @param onChange - 文件变化回调函数
 * @param buttonText - 自定义上传按钮文本
 * @param dragText - 拖拽区域提示文本
 * @param dragSubText - 拖拽区域副标题
 * @param maxCount - 最大文件数量
 * @param accept - 允许的文件类型
 * @param maxSize - 文件大小限制（MB）
 * @param action - 上传地址
 * @param beforeUpload - 上传前的回调
 * @param onPreview - 预览文件回调
 * @param onRemove - 删除文件回调
 * @param onDownload - 下载文件回调
 * @param disabled - 是否禁用
 * @param multiple - 是否支持多选
 * @param customUploadList - 自定义上传列表渲染函数
 * @param useCustomList - 是否启用自定义列表
 *
 * ## 使用示例
 *
 * ### 基础按钮上传
 * ```tsx
 * <Upload
 *   action="/api/upload"
 *   onChange={(fileList) => console.log(fileList)}
 * >
 *   点击上传
 * </Upload>
 * ```
 *
 * ### 拖拽上传
 * ```tsx
 * <Upload
 *   variant="drag"
 *   action="/api/upload"
 *   dragText="点击或拖拽文件到此区域上传"
 *   dragSubText="支持单个或批量上传"
 * />
 * ```
 *
 * ### 头像上传
 * ```tsx
 * <Upload
 *   variant="avatar"
 *   action="/api/upload"
 *   accept="image/*"
 *   maxCount={1}
 *   showUploadList={false}
 * />
 * ```
 *
 * ### 图片上传
 * ```tsx
 * <Upload
 *   variant="picture"
 *   action="/api/upload"
 *   accept="image/*"
 *   maxCount={5}
 *   listType="picture-card"
 * />
 * ```
 *
 * ### 受控模式
 * ```tsx
 * const [fileList, setFileList] = useState([]);
 *
 * <Upload
 *   fileList={fileList}
 *   onChange={setFileList}
 *   action="/api/upload"
 * />
 * ```
 *
 * ### 文件限制
 * ```tsx
 * <Upload
 *   accept=".pdf,.doc,.docx"
 *   maxSize={10}
 *   maxCount={3}
 *   action="/api/upload"
 * />
 * ```
 *
 * ### 自定义上传列表
 * ```tsx
 * <Upload
 *   useCustomList
 *   customUploadList={({ file, onRemove, onPreview, onDownload }) => (
 *     <div className="my-upload-item">
 *       <span>{file.name}</span>
 *       <div>
 *         <button onClick={() => onPreview?.(file)}>预览</button>
 *         <button onClick={() => onDownload?.(file)}>下载</button>
 *         <button onClick={() => onRemove(file)}>删除</button>
 *       </div>
 *     </div>
 *   )}
 *   action="/api/upload"
 * />
 * ```
 *
 * ### 使用默认自定义列表样式
 * ```tsx
 * <Upload
 *   useCustomList
 *   action="/api/upload"
 *   onPreview={(file) => {
 *     // 自定义预览逻辑
 *     window.open(file.url);
 *   }}
 *   onDownload={(file) => {
 *     // 自定义下载逻辑
 *     console.log('下载文件:', file.name);
 *   }}
 * />
 * ```
 */
export const Upload = ({
  size = undefined,
  variant = 'button',
  showUploadList = true,
  fileList,
  onChange,
  buttonText = '上传文件',
  dragText = '',
  dragSubText = '',
  maxCount,
  accept,
  maxSize,
  className,
  children,
  beforeUpload,
  customUploadList,
  useCustomList = false,
  onPreview,
  onRemove,
  onDownload,
  ...props
}: CustomUploadProps) => {
  const [internalFileList, setInternalFileList] = useState<UploadFile[]>([]);
  const [hover, setHover] = useState(false);
  const uploadRef = useRef<any>(null);

  // 获取当前文件列表
  const currentFileList = fileList ?? internalFileList;

  // 处理文件变化
  const handleChange: UploadProps['onChange'] = (info) => {
    const newFileList = [...info.fileList];

    if (fileList === undefined) {
      setInternalFileList(newFileList);
    }
    onChange?.(newFileList);

    // 处理上传状态消息
    const { status } = info.file;
    if (status === 'done') {
      message.success(`${info.file.name} 文件上传成功`);
    } else if (status === 'error') {
      message.error(`${info.file.name} 文件上传失败`);
    }
  };

  // 处理文件删除
  const handleRemove = (file: UploadFile) => {
    const newFileList = currentFileList.filter((item) => item.uid !== file.uid);
    if (fileList === undefined) {
      setInternalFileList(newFileList);
    }
    onChange?.(newFileList);
    onRemove?.(file);
  };

  // 处理文件预览
  const handlePreview = (file: UploadFile) => {
    onPreview?.(file);
  };

  // 处理文件下载
  const handleDownload = (file: UploadFile) => {
    if (onDownload) {
      onDownload(file);
    } else if (file.url || file.response?.url) {
      const url = file.url || file.response?.url;
      const link = document.createElement('a');
      link.href = url;
      link.download = file.name || 'download';
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
    }
  };

  // 渲染自定义上传列表
  const renderCustomUploadList = () => {
    if (!useCustomList || currentFileList.length === 0) {
      return null;
    }

    const listRenderer = customUploadList || defaultCustomListItem;

    return (
      <div className="rg-upload-custom-list">
        {currentFileList.map((file, index) => (
          <div key={file.uid} className="rg-upload-custom-list-item w-[334px]">
            {listRenderer({
              file,
              index,
              onRemove: handleRemove,
              onPreview: handlePreview,
              onDownload: handleDownload,
            })}
          </div>
        ))}
      </div>
    );
  };

  // 默认自定义列表项渲染
  const defaultCustomListItem = (item: CustomUploadListItem) => {
    const { file, onRemove, onPreview, onDownload } = item;
    const isImage = file.type?.startsWith('image/');

    return (
      <div className="rg-upload-default-item mb-2 flex  items-center justify-between !px-2 !py-0 hover:!bg-white">
        <div className="rg-upload-item-info flex items-center">
          <SvgIcon icon="upload-file" size={12} className="!text-text-5" />
          <span
            className={`rg-upload-item-name w-[110px] truncate !text-cn-14 text-@brand-color ${
              file.status === 'error' ? '!text-@error-color' : ''
            }`}
            title={file.name}
          >
            {file.name}
          </span>
        </div>
        <div className="rg-upload-item-status w-[100px]">
          {file.status === 'uploading' && (
            <div className="rg-upload-item-progress flex items-center gap-2">
              <div className="h-2 flex-1 overflow-hidden rounded-full bg-gray-200">
                <div
                  className="h-full bg-blue-500 transition-all duration-300 ease-out"
                  style={{ width: `${file.percent || 0}%` }}
                />
              </div>
              <span className="min-w-[40px] text-xs text-gray-600">
                {file.percent ? `${Math.round(file.percent)}%` : '0%'}
              </span>
            </div>
          )}
          {file.status === 'done' && (
            <div className="rg-upload-item-success flex items-center justify-end gap-1">
              <SvgIcon icon="upload-success" size={12} />
            </div>
          )}
          {file.status === 'error' && (
            <div className="rg-upload-item-error  flex items-center justify-end gap-1">
              <span
                className="cursor-pointer text-cn-12 text-@brand-color transition-opacity hover:opacity-80"
                onClick={() => retry(file)}
              >
                点击重试
              </span>
              <SvgIcon icon="upload-warn" size={12} />
            </div>
          )}
        </div>
        <div className="flex items-center">
          <SvgIcon icon="delete-icon" className="t cursor-pointer" onClick={() => onRemove(file)} />
        </div>
      </div>
    );
  };

  // 处理上传前验证
  const handleBeforeUpload = (file: File) => {
    // 文件类型验证
    if (accept) {
      const acceptTypes = accept.split(',').map((type) => type.trim());
      const fileExtension = `.${file.name.split('.').pop()?.toLowerCase()}`;
      const mimeType = file.type;

      const isValidType = acceptTypes.some((type) => {
        if (type.startsWith('.')) {
          return fileExtension === type.toLowerCase();
        }
        return mimeType.startsWith(type.replace('*', ''));
      });

      if (!isValidType) {
        message.error(`不支持的文件类型，请上传 ${accept} 格式的文件`);
        return false;
      }
    }

    // 文件大小验证
    if (maxSize && file.size > maxSize * 1024 * 1024) {
      message.error(`文件大小不能超过 ${maxSize}MB`);
      return false;
    }

    // 文件数量验证
    if (maxCount && currentFileList.length >= maxCount) {
      message.error(`最多只能上传 ${maxCount} 个文件`);
      return false;
    }

    return beforeUpload?.(file) ?? true;
  };

  // 生成样式类名
  const getClassName = () => {
    return cn('rg-upload', `rg-upload--${size}`, `rg-upload--${variant}`, className);
  };

  // 获取实际的 showUploadList 配置
  const getShowUploadList = () => {
    if (useCustomList) {
      return false; // 使用自定义列表时隐藏默认列表
    }
    return showUploadList;
  };

  // 自定义上传请求函数
  const customRequest = async (options: any) => {
    const { file, onProgress, onSuccess, onError, data, headers } = options;

    try {
      // 创建 FormData
      const formData = new FormData();
      formData.append('file', file);

      // 添加额外的数据
      if (data) {
        Object.keys(data).forEach((key) => {
          formData.append(key, data[key]);
        });
      }

      // 使用apiClient发起上传请求
      const requestHeaders: Record<string, string> = {
        'Content-Type': 'multipart/form-data',
        ...headers,
      };

      const response = await apiClient.post({
        url: props.action,
        data: formData,
        headers: requestHeaders,
        onUploadProgress: (progressEvent) => {
          if (progressEvent.total) {
            const percent = Math.round((progressEvent.loaded / progressEvent.total) * 100);
            onProgress?.({ percent });
          }
        },
      });

      onSuccess?.(response, file);
    } catch (error) {
      console.error('上传失败:', error);
      onError?.(error);
    }
  };

  const retry = async (file: UploadFile) => {
    console.log('retry file', file);
    if (!file.originFileObj) {
      console.error('缺少文件对象');
      return;
    }

    // 重置文件状态为上传中
    const uploadingFile = {
      ...file,
      status: 'uploading' as const,
      percent: 0,
      error: undefined,
    };

    // 更新文件列表状态
    const updateFileList = (updatedFile: UploadFile) => {
      const newFileList = currentFileList.map((f) => (f.uid === file.uid ? updatedFile : f));
      if (fileList === undefined) {
        setInternalFileList(newFileList);
      }
      onChange?.(newFileList);
      return newFileList;
    };

    // 先更新为上传中状态
    updateFileList(uploadingFile);

    // 使用 customRequest 进行重新上传
    await customRequest({
      file: file.originFileObj,
      onProgress: ({ percent }: { percent: number }) => {
        const progressFile = {
          ...uploadingFile,
          percent,
        };
        updateFileList(progressFile);
      },
      onSuccess: (response: any) => {
        const successFile = {
          ...uploadingFile,
          status: 'done' as const,
          percent: 100,
          response,
        };
        updateFileList(successFile);
        console.log('重新上传成功', response);
      },
      onError: (error: any) => {
        console.error('重新上传失败:', error);
        const errorFile = {
          ...uploadingFile,
          status: 'error' as const,
          error: error instanceof Error ? error : new Error('上传失败'),
        };
        updateFileList(errorFile);
      },
      data: props.data,
      headers: props.headers,
    });
  };
  // 渲染上传组件和自定义列表的容器
  const renderUploadContainer = (uploadComponent: ReactNode) => {
    if (!useCustomList) {
      return uploadComponent;
    }

    return (
      <div className="rg-upload-container">
        {uploadComponent}
        {renderCustomUploadList()}
      </div>
    );
  };

  // 拖拽上传
  if (variant === 'drag') {
    const uploadComponent = (
      <AntdUpload.Dragger
        {...props}
        ref={uploadRef}
        fileList={currentFileList}
        onChange={handleChange}
        beforeUpload={handleBeforeUpload}
        showUploadList={getShowUploadList()}
        className={getClassName()}
        customRequest={customRequest}
        action={undefined}
      >
        <p className="ant-upload-drag-icon">
          <SvgIcon icon="upload-dragger" size={48} />
        </p>
        <p className="ant-upload-text">{dragText}</p>
        <p className="ant-upload-hint">
          {dragSubText || (
            <>
              <span className="!text-@brand-color">点击上传</span>
              <span> / 或拖拽文件到此处</span>
            </>
          )}
        </p>
      </AntdUpload.Dragger>
    );
    return renderUploadContainer(uploadComponent);
  }

  // 头像上传
  if (variant === 'avatar') {
    const uploadComponent = (
      <AntdUpload
        {...props}
        ref={uploadRef}
        fileList={currentFileList}
        onChange={handleChange}
        beforeUpload={handleBeforeUpload}
        showUploadList={getShowUploadList()}
        className={getClassName()}
        listType="picture-circle"
        customRequest={customRequest}
        action={undefined}
      >
        {children || (
          <div>
            <UploadOutlined />
            <div style={{ marginTop: 8 }}>上传头像</div>
          </div>
        )}
      </AntdUpload>
    );
    return renderUploadContainer(uploadComponent);
  }

  // 图片上传
  if (variant === 'picture') {
    const uploadComponent = (
      <AntdUpload
        {...props}
        ref={uploadRef}
        fileList={currentFileList}
        onChange={handleChange}
        beforeUpload={handleBeforeUpload}
        showUploadList={getShowUploadList()}
        className={getClassName()}
        listType="picture-card"
        customRequest={customRequest}
        action={undefined}
      >
        {children || (
          <div>
            <UploadOutlined />
            <div style={{ marginTop: 8 }}>上传图片</div>
          </div>
        )}
      </AntdUpload>
    );
    return renderUploadContainer(uploadComponent);
  }

  // 按钮上传（默认）
  const uploadComponent = (
    <AntdUpload
      {...props}
      ref={uploadRef}
      fileList={currentFileList}
      onChange={handleChange}
      beforeUpload={handleBeforeUpload}
      showUploadList={getShowUploadList()}
      className={getClassName()}
      customRequest={customRequest}
      action={undefined}
    >
      <Button
        className="upload-button !bg-fill-1"
        size={size}
        onMouseEnter={() => {
          setHover(true);
        }}
        onMouseLeave={() => {
          setHover(false);
        }}
      >
        <SvgIcon icon={hover ? 'upload-cloud-active' : 'upload-cloud'} size={16} />
        {buttonText}
      </Button>
    </AntdUpload>
  );
  return renderUploadContainer(uploadComponent);
};

export default Upload;
